package cc.rome753.wat;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;

import org.webrtc.BuiltinAudioDecoderFactoryFactory;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.EglBase;
import org.webrtc.MyVideoDecoderFactory;
import org.webrtc.MyVideoEncoderFactory;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.VideoCodecInfo;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

    PeerConnectionFactory peerConnectionFactory;
    EglBase.Context eglBaseContext;

    PeerClientFragment frontClient;
    PeerClientFragment backClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "onCreate()");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onDestroy() {
        Log.i(TAG, "onDestroy()");
        super.onDestroy();
        releaseAll();
    }

    public void onclick(View view) {
        int id = view.getId();
        if (id == R.id.fl_local) {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            if (frontClient == null) {
                frontClient = new PeerClientFragment(true);
                transaction.add(R.id.fl_local, frontClient);
            } else {
                transaction.remove(frontClient);
                frontClient = null;
            }
            transaction.commit();
        } else if (id == R.id.fl_remote) {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            if (backClient == null) {
                backClient = new PeerClientFragment(false);
                transaction.add(R.id.fl_remote, backClient);
            } else {
                transaction.remove(backClient);
                backClient = null;
            }
            transaction.commit();
        }
    }

    public EglBase.Context getEglBaseContext () {
        if (eglBaseContext == null) {
            eglBaseContext = EglBase.create().getEglBaseContext();
        }
        return eglBaseContext;
    }

    public PeerConnectionFactory getPeerConnectionFactory() {
        if (peerConnectionFactory == null) {
            EglBase.Context eglBaseContext = getEglBaseContext();

            // create PeerConnectionFactory
            PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions
                    .builder(this)
                    .createInitializationOptions());
            PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();

            MyVideoEncoderFactory myVideoEncoderFactory =
                    new MyVideoEncoderFactory(eglBaseContext, true, true);
            VideoCodecInfo[] einfos = myVideoEncoderFactory.getSupportedCodecs();
            if (einfos != null) {
                for (VideoCodecInfo vci : einfos) {
                    Log.i(TAG, "encoder name: " + vci.name);
                }
            }
            DefaultVideoDecoderFactory defaultVideoDecoderFactory =
                    new DefaultVideoDecoderFactory(eglBaseContext);
            VideoCodecInfo[] dinfos = defaultVideoDecoderFactory.getSupportedCodecs();
            if (dinfos != null) {
                for (VideoCodecInfo vci : dinfos) {
                    Log.i(TAG, "decoder name: " + vci.name);
                }
            }

            MyVideoDecoderFactory myVideoDecoderFactory = new MyVideoDecoderFactory(eglBaseContext);
            VideoCodecInfo[] minfos = myVideoDecoderFactory.getSupportedCodecs();
            if (minfos != null) {
                for (VideoCodecInfo vci : minfos) {
                    Log.i(TAG, "my decoder name: " + vci.name);
                }
            }

            BuiltinAudioDecoderFactoryFactory audioDecoderFactoryFactory = new BuiltinAudioDecoderFactoryFactory();

            peerConnectionFactory = PeerConnectionFactory.builder()
                    .setOptions(options)
                    .setVideoEncoderFactory(myVideoEncoderFactory)
                    .setVideoDecoderFactory(myVideoDecoderFactory)
//                    .setAudioDecoderFactoryFactory(audioDecoderFactoryFactory)
                    .setAudioDeviceModule(createJavaAudioDevice())
                    .createPeerConnectionFactory();
        }

        return peerConnectionFactory;
    }

    private void releaseAll() {
        if (peerConnectionFactory != null) {
            peerConnectionFactory.dispose();
            peerConnectionFactory = null;
        }
    }

    AudioDeviceModule createJavaAudioDevice() {
        // Set audio record error callbacks.
        JavaAudioDeviceModule.AudioRecordErrorCallback audioRecordErrorCallback = new JavaAudioDeviceModule.AudioRecordErrorCallback() {
            @Override
            public void onWebRtcAudioRecordInitError(String errorMessage) {
                Log.e(TAG, "onWebRtcAudioRecordInitError: " + errorMessage);
            }

            @Override
            public void onWebRtcAudioRecordStartError(
                    JavaAudioDeviceModule.AudioRecordStartErrorCode errorCode, String errorMessage) {
                Log.e(TAG, "onWebRtcAudioRecordStartError: " + errorCode + ". " + errorMessage);
            }

            @Override
            public void onWebRtcAudioRecordError(String errorMessage) {
                Log.e(TAG, "onWebRtcAudioRecordError: " + errorMessage);
            }
        };

        JavaAudioDeviceModule.AudioTrackErrorCallback audioTrackErrorCallback = new JavaAudioDeviceModule.AudioTrackErrorCallback() {
            @Override
            public void onWebRtcAudioTrackInitError(String errorMessage) {
                Log.e(TAG, "onWebRtcAudioTrackInitError: " + errorMessage);
            }

            @Override
            public void onWebRtcAudioTrackStartError(
                    JavaAudioDeviceModule.AudioTrackStartErrorCode errorCode, String errorMessage) {
                Log.e(TAG, "onWebRtcAudioTrackStartError: " + errorCode + ". " + errorMessage);
            }

            @Override
            public void onWebRtcAudioTrackError(String errorMessage) {
                Log.e(TAG, "onWebRtcAudioTrackError: " + errorMessage);
            }
        };

        // Set audio record state callbacks.
        JavaAudioDeviceModule.AudioRecordStateCallback audioRecordStateCallback = new JavaAudioDeviceModule.AudioRecordStateCallback() {
            @Override
            public void onWebRtcAudioRecordStart() {
                Log.i(TAG, "Audio recording starts");
            }

            @Override
            public void onWebRtcAudioRecordStop() {
                Log.i(TAG, "Audio recording stops");
            }
        };

        // Set audio track state callbacks.
        JavaAudioDeviceModule.AudioTrackStateCallback audioTrackStateCallback = new JavaAudioDeviceModule.AudioTrackStateCallback() {
            @Override
            public void onWebRtcAudioTrackStart() {
                Log.i(TAG, "Audio playout starts");
            }

            @Override
            public void onWebRtcAudioTrackStop() {
                Log.i(TAG, "Audio playout stops");
            }
        };

        JavaAudioDeviceModule.SamplesReadyCallback samplesReadyCallback = new JavaAudioDeviceModule.SamplesReadyCallback() {
            @Override
            public void onWebRtcAudioRecordSamplesReady(JavaAudioDeviceModule.AudioSamples audioSamples) {
                Log.i(TAG, "onWebRtcAudioRecordSamplesReady(), " + toString(audioSamples), new Exception("test"));
            }

            private String toString(JavaAudioDeviceModule.AudioSamples audioSamples) {
                if (audioSamples == null) {
                    return "";
                }

                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append("format: ");
                stringBuilder.append(audioSamples.getAudioFormat());
                stringBuilder.append("sample rate: ");
                stringBuilder.append(audioSamples.getSampleRate());
                stringBuilder.append("channel count: ");
                stringBuilder.append(audioSamples.getChannelCount());
                stringBuilder.append("data: ");
                stringBuilder.append(audioSamples.getData() == null ? -1: audioSamples.getData().length);

                return  stringBuilder.toString();
            }
        };

        return JavaAudioDeviceModule.builder(this)
                .setSamplesReadyCallback(samplesReadyCallback)
                .setUseHardwareAcousticEchoCanceler(true)
                .setUseHardwareNoiseSuppressor(true)
                .setAudioRecordErrorCallback(audioRecordErrorCallback)
                .setAudioTrackErrorCallback(audioTrackErrorCallback)
                .setAudioRecordStateCallback(audioRecordStateCallback)
                .setAudioTrackStateCallback(audioTrackStateCallback)
                .createAudioDeviceModule();
    }
}
